using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using NAudio.Wave;
using UPKAndUDKUnpackTools.Tools;

namespace UPKAndUDKUnpackTools;

public partial class Form1 : Form
{
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

    private static readonly IntPtr HWND_TOPMOST = new(-1);
    private const uint SWP_NOSIZE = 0x0001;
    private const uint SWP_NOMOVE = 0x0002;
    private const uint SWP_SHOWWINDOW = 0x0040;

    private void SetTopMost()
    {
        SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
    }
    private static string filePath = "";
    private static string finalOutputDir = "";
    private static int type;
    private static string upkType = "";

    private static int fileCount;
    private Mp3FileReader mp3Reader;
    private WaveOut waveOutDevice;

    public Form1()
    {
        InitializeComponent();
        var writer = new TextBoxWriter(outLog);
        Console.SetOut(writer);
        UdkProcessor.OnProgressUpdate += ProgressBar;
        UpkProcessor.OnProgress += ProgressBar;
        UdkExporter.pValueOnUpdated += UpdateProgress;
        UpkExporter.pValueOnUpdated += UpdateProgress;
    }

    private static bool isRun { get; set; }
    public static bool noLighting { get; private set; }
    public static bool sounds { get; private set; }

    /// <summary>
    ///     在新线程中更新进度条的值，直到达到指定的进度。
    /// </summary>
    /// <param name="progress">要更新到的进度值，最大为100。</param>
    private void ProgressBar(int progress)
    {
        var d = 0;
        // 在新线程中运行进度更新，避免UI线程阻塞
        Task.Run(() =>
        {
            while (isRun)
            {
                // 检查是否已达到目标进度
                if (d == progress)
                {
                    // 如果进度达到100，则退出任务
                    if (d == 100)
                    {
                        isRun = false;
                        return;
                    }

                    // 否则，继续下一次循环
                    continue;
                }

                // 更新进度条的值
                d++;
                Task.Delay(1000);
                var d1 = d;
                dungeonProgressBar1.Invoke(() => dungeonProgressBar1.Value = d1);
            }
        });
    }

    private void UpdateProgress(int value)
    {
        dungeonProgressBar1.Value = value;
    }


    private async void upkFiles_Click(object sender, EventArgs e)
    {
        type = 1;
        filePath = DirectoryManager.CreateFolder("UPK");
        DirectoryManager.OpenDirectory(filePath);
        MessageBox.Show("请将UPK文件放进打开的目录中！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
        await LoadFilesAsync(filePath);
    }

    private async void udkFiles_Click(object sender, EventArgs e)
    {
        type = 2;
        filePath = DirectoryManager.CreateFolder("UDK");
        DirectoryManager.OpenDirectory(filePath);
        MessageBox.Show("请将UDK文件放进打开的目录中！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
        await LoadFilesAsync(filePath);
    }

    private void saveParam_Click(object sender, EventArgs e)
    {
        noLighting = skipLightMap.Checked;
        sounds = outSounds.Checked;
        switch (fileType.Text)
        {
            case "音频":
                finalOutputDir = DirectoryManager.CreateFolder("Sounds");
                upkType = "1";
                break;
            case "模型":
                finalOutputDir = DirectoryManager.CreateFolder("Models");
                upkType = "2";
                break;
            case "动画":
                finalOutputDir = DirectoryManager.CreateFolder("Anims");
                upkType = "3";
                break;
            case "地图":
                finalOutputDir = DirectoryManager.CreateFolder("Maps");
                break;
            default:
                MessageBox.Show("请选择文件类型！");
                return;
        }

        MessageBox.Show("参数设置完成！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
        groupBox4.Enabled = true;
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        if (ToolExporter.ExportToolsExe([
                "UnPack.exe", "decompress.exe", "Repair.exe", "umodel64.exe", "SDL2_64.dll", "FsbExtractor.exe"
            ]))
        {
            MessageBox.Show("程序初始化成功！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            dungeonProgressBar1.Maximum = 100;
            fileList.RowHeadersVisible = false;
        }
        else
        {
            MessageBox.Show("程序初始化失败！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
            Application.Exit();
        }
    }

    private async Task LoadFilesAsync(string directoryPath)
    {
        try
        {
            var files = await Task.Run(() => Directory.GetFiles(directoryPath));
            fileCount = files.Length;

            fileList.Invoke(() => fileList.Rows.Clear());
            var i = 1;

            foreach (var file in files)
            {
                var fileN = Path.GetFileName(file);
                var i1 = i;
                fileList.Invoke(() => fileList.Rows.Add(i1, fileN, file));
                i++;
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show($"读取文件列表时出错： {ex.Message}");
        }
    }

    private async void startHandle_Click(object sender, EventArgs e)
    {
        try
        {
            // 播放Start.mp3
            _ = PlayStartSoundAsync("Start");

            ProgressBar(0);
            dungeonProgressBar1.ProgressColorA = Color.ForestGreen;
            dungeonProgressBar1.ProgressColorB = Color.Lime;

            await Task.Run(() =>
            {
                switch (type)
                {
                    case 1:
                        isRun = true;
                        UpkProcessor.ProcessUpkFiles(filePath, "outUpk");
                        UpkProcessor.ProcessFiles(outSounds.Checked);
                        break;
                    case 2:
                        isRun = true;
                        UdkProcessor.ProcessUdkFiles(filePath, "outUdk");
                        UdkProcessor.ProcessFiles();
                        break;
                }
            });

            _ = PlayStartSoundAsync("End");
            MessageBox.Show("处理完成！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"错误: {ex.Message}");
        }
    }

    /// <summary>
    /// 异步播放开始声音。
    /// </summary>
    /// <param name="sound">声音文件名。</param>
    private async Task PlayStartSoundAsync(string sound)
    {
        // 尝试获取资源流
        try
        {
            // 使用 Assembly 类获取当前执行的程序集
            // 从资源文件中获取指定声音的 MP3 资源流
            await using var stream = Assembly.GetExecutingAssembly()
                .GetManifestResourceStream($"UPKAndUDKUnpackTools.Resources.{sound}.mp3");

            // 如果资源流为 null，则输出资源未找到并返回
            if (stream == null)
            {
                Console.WriteLine("资源未找到。");
                return;
            }

            // 创建一个 MP3 读取器
            mp3Reader = new Mp3FileReader(stream);
            // 创建一个音频输出设备对象
            waveOutDevice = new WaveOut();
            // 初始化音频输出设备
            waveOutDevice.Init(mp3Reader);
            // 开始播放音频
            waveOutDevice.Play();

            // 在后台任务中等待播放结束
            await Task.Run(() =>
            {
                // 当音频正在播放时，循环等待
                while (waveOutDevice.PlaybackState == PlaybackState.Playing) Task.Delay(100).Wait();
            });
        }
        // 捕获并处理播放过程中的异常
        catch (Exception ex)
        {
            Console.WriteLine($"播放失败: {ex.Message}");
        }
        // 确保资源被正确释放
        finally
        {
            await mp3Reader.DisposeAsync();
            waveOutDevice?.Dispose();
        }
    }


    private async void startOut_Click(object sender, EventArgs e)
    {
        dungeonProgressBar1.Value = 0;
        dungeonProgressBar1.Maximum = fileCount;
        dungeonProgressBar1.ProgressColorA = Color.Brown;
        dungeonProgressBar1.ProgressColorB = Color.Red;
        var filesCurrentDir = Directory.GetCurrentDirectory();
        var upkFilePath = Path.Combine(filesCurrentDir, "unlockedUpk");
        var udkFilePath = Path.Combine(filesCurrentDir, "unlockedUdk");
        var upkTemp = DirectoryManager.CreateFolder("temp");
        _ = PlayStartSoundAsync("Start");

        await Task.Run(() =>
        {
            switch (type)
            {
                case 1:
                    if (outSounds.Checked)
                    {
                        UpkExporter.ExportSoundForUpkFiles(upkFilePath, upkTemp, finalOutputDir);
                        return;
                    }

                    UpkExporter.ExportModelsAndAnimsForUpkFiles(upkFilePath, finalOutputDir);
                    UpkExporter.GetStatus(upkType);
                    break;
                case 2:
                    UdkExporter.ExportModelsForUdkFiles(udkFilePath, finalOutputDir);
                    UdkExporter.GetStatus();
                    break;
            }
        });

        dungeonProgressBar1.Invoke(() => dungeonProgressBar1.Value = 100);
        _ = PlayStartSoundAsync("End");
        MessageBox.Show("导出完成！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
        DirectoryManager.OpenDirectory(finalOutputDir);
        DirectoryManager.CleanUpDirectories();
    }

    private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
    {
        _ = PlayStartSoundAsync("Thanks");
        Process.Start(new ProcessStartInfo("https://tls.lovemmd.cn/static/img/Sponsorship-HD.85899b2d.png")
        {
            UseShellExecute = true
        });
    }

    private string fsbFolderPath;

    private void selectFsb_Click(object sender, EventArgs e)
    {
        var openFolder = new FolderBrowserDialog();
        if (openFolder.ShowDialog(this) != DialogResult.OK) return;
        fsbFolderPath = openFolder.SelectedPath;
        aloneTextBox1.Text = fsbFolderPath;
    }

    private void startOutFsb_Click(object sender, EventArgs e)
    {
        SetTopMost();
        _ = PlayStartSoundAsync("Start");
        var files = Directory.GetFiles(fsbFolderPath, "*.fsb", SearchOption.AllDirectories);
        dungeonProgressBar1.Value = 0;
        dungeonProgressBar1.Maximum = files.Length;
        foreach (var file in files)
        {
            RunProgram(file);
            dungeonProgressBar1.Value++;
        }
        _ = PlayStartSoundAsync("End");
    }

    private static void RunProgram(string fsbPath)
    {
        var startInfo = new ProcessStartInfo
        {
            FileName = "FsbExtractor.exe",
            Arguments = $"/c /v0 /s1 /O: /L:log.txt {fsbPath}",
            WindowStyle = ProcessWindowStyle.Hidden,
            CreateNoWindow = true,
            UseShellExecute = false
        };
        using var process = Process.Start(startInfo);
        process?.WaitForExit();
        const string tempFile = "temp$$$$.mp3";
        if (!File.Exists(tempFile)) return;
        var fsbDirectory = Path.GetDirectoryName(fsbPath);
        Debug.Assert(fsbDirectory != null, nameof(fsbDirectory) + " != null");
        var newFileName = Path.Combine(fsbDirectory, $"{Path.GetFileNameWithoutExtension(fsbPath)}.mp3");
        File.Move(tempFile, newFileName);
        Console.WriteLine($"已移动并重命名为：{newFileName}");
        File.Delete(fsbPath);
        Console.WriteLine($"已删除 FSB 文件：{fsbPath}");
    }

    private void outHighLv_Click(object sender, EventArgs e)
    {
        var filesCurrentDir = Directory.GetCurrentDirectory();
        var upkFilePath = Path.Combine(filesCurrentDir, "unlockedUpk");
        var udkFilePath = Path.Combine(filesCurrentDir, "unlockedUdk");
        if (!outHighLv.Checked) return;
        MessageBox.Show("本功能将创建符号链接，请确保以管理员身份运行本程序，否则可能无法创建链接。", "提示", MessageBoxButtons.OK,
            MessageBoxIcon.Information);
        Console.WriteLine("正在为UPK创建符号链接...");
        SymbolicLinkCreator.CreateLinksFromSelectedFolder(upkFilePath);
        Console.WriteLine("正在为UDK创建符号链接...");
        SymbolicLinkCreator.CreateLinksFromSelectedFolder(udkFilePath);
    }
}